Matplotlib是建立在 NumPy数组基础上的多平台数据可视化程序库。
Matplotlib最重要的特性之一就是具有良好的操作系统兼容性和图形显示底层接口兼容性( graphics backend)。 Matplotlib支持几十种图形显示接口与输出格式,这使得用户无论在哪种操作系统上都可以输出自己想要的图形格式。这种跨平台、面面俱到的特点已经成为 Matplotlib最强大的功能之一, Matplotlib也因此吸引了大量用户,进而形成了一个活跃的开发者团队,晋升为 Python科学领域不可或缺的强大武器。
Matplotlib常用技巧
导入 Matplotlib
设置绘图样式
用不用show()?如何显示图形
在脚本中画图
如果你在一个脚本文件中使用 Matplotlib,那么显示图形的时候必须使用plt.show()。plt.show()会启动一个事件循环( event lop),并找到所有当前可用的图形对象,然后打开一个或多个交互式窗口显示图形。
plt,show()这行代码在后面完成了许多事情,它需要与你使用的操作系统的图形显示接口进行交互。虽然具体的操作细节会因操作系统和安装过程不同而有很大的差异,但是 Matplotlib为你隐藏所有的细节,非常省心。
不过有一点需要注意,一个 Python会话( session)中只能使用一次plt.show(),因此通常都把它放在脚本的最后。多个plt.show()命令会导致难以预料的显示异常,应该尽量避免。
在IPython shell中画图
在IPython Notebook中画图
将图形保存为文件
当你保存图形文件时,不需要使用plt.show()。
两种画图接口
Matplotlib有一个容易让人混淆的特性,就是它的两种画图接口,一个是便捷的 MATLAB风格接口,另一个是功能更强大的面向对象接口。
MATLAB风格接口
Matplotlib最初作为 MATLAB用户的 Python替代品,许多语法都和MATLAB类似。 MATLAB风格的工具位于 pyplot(plt)接口中。
这种接口最重要的特性是有状态的( stateful):它会持续跟踪“当前的图形和坐标轴,所有plt命令都可以应用。你可以用plt.gcf()(获取当前图形)和plt,gca()(获取当前坐标轴)来查看具体信息。
虽然这个有状态的接口画起来图又快又方便,但是也很容易出问题。当创建上面的第二个子图时,怎么才能回到第一个子图,并增加新内容呢?虽然用 MATLAB风格接口也能实现,但未免过于复杂,好在还有一种更好的办法!
面向对象接口
面向对象接口可以适应更复杂的场景,更好地控制你自己的图形。在面向对象接口中,画图函数不再受到当前“活动”图形或坐标轴的限制,而变成了显式的 Figure和Axes的方法。
虽然在画简单图形时,选择哪种绘图风格主要看个人喜好,但是在画比较复杂的图形时,面向对象方法会更方便。在本章中,我们将在MATLAB风格接口与面向对象接口间来回转换,具体内容根据实际情况而定。在绝大多数场中,plt.plot()与ax.plot()的差异非常小,但是其中会有一些陷阱。
简易线形图
在 Matplotlib里面, figure(plt.Figure类的一个实例)可以被看成是个能够容纳各种坐标轴、图形、文字和标签的容器。就像你在图中看到的那样,axes(plt.Axes类的一个实例)是一个带有刻度和标签的矩形,最终会包含所有可视化的图形元素。
调整图形:线条的颜色与风格
如果不指定颜色, Matplotlib就会为多条线自动循环使用一组默认的颜色。
与之类似,也可以用linestyle调整线条的风格。
一种更简洁的方式,则可以将linstyle和 color编码组合起来,作为plt.plot()函数的一个非关键字参数使用。
调整图形:坐标轴上下限
如果你想要让坐标轴逆序显示,那么也可以逆序设置坐标轴刻度值。
还有一个方法是plt,axis()(注意不要搞混axes和axis)。通过传入[xmin,xmax,ymin,ymax]对应的值,plt,axis()方法可以让你用一行代码设置x或y的限值。
plt axis()还可以按照图形的内容自动收紧坐标轴,不留空白区域。
还可以xy轴单位长度相等。
设置图形标签
图形标题与坐标轴标题是最简单的标签。
Matplotlib内置了一个简单快速的方法,可以用来创建图例,那就是plt. legend()。
在用面向对象接口画图时,不需要单独调用这些函数,通常采用ax.set()方法一次性设置所有的属性是更简便的方法。
简易散点图
另一种常用的图形是简易散点图( scatter plot),与线形图类似。这种图形不再由线段连接,而是由独立的点、圆圈或其他形状构成。开始的时候需要导入函数。
用plt.plot画散点图
函数的第三个参数是一个字符,表示图形符号的类型。
这些代码还可以与线条、颜色代码组合起来,画出一条连接散点的线。
用plt.scatter画散点图
另一个可以创建散点图的函数是plt.scatter。它的功能非常强大其用法与plt.plot函数类似。
plt scatter与p1t.plot的主要差别在于,前者在创建散点图时具有更高的灵活性,可以单独控制每个散点与数据匹配,也可以让每个散点具有不同的属性(大小、表面颜色、边框颜色、透明度等)。
plot与scatter:效率对比
plt.plot与plt.scatter除了特征上的差异之外,还有什么影响我们选择的因素呢?在数据量较小的时候,两者在效率上的差异不大。但是当数据变大到几千个散点时,plt.plot的效率将大大高于plt.scatter。这是由于plt.scatter会对每个散点进行单独的大小与颜色的渲染,因此渲染器会消耗更多的资源。而在plt.plot中,散点基本都彼此复制,因此整个数据集中所有点的颜色、尺寸只需要配置一次。由于这两种方法在处理大型数据集时有很大的性能差异,因此面对大型数据集时,plt.plot方法比plt.scatter方法好。
可视化异常处理
基本误差线
基本误差线( errorbar)可以通过一个 Matplotlib函数来创建。
除了这些选项之外,你还可以设置水平方向的误差线(xerr)、单侧误差线( one-sided errorbar),以及其他形式的误差线。
连续误差
密度图与等高线图
Matplotlib提供了三个函数来解决这个问题:用plt.contour画等高线图、用plt.contourf画带有填充色的等高线图( filled contour plot)的色彩、用plt.imshow显示图形。
三维函数的可视化
当图形中只使用一种颜色时,默认使用虚线表示负数,使用实线表示正数。我们可以通过plt.contourf()函数来填充等高线图,它的语法和plt.contour()是一样的。
还可以通过plt. colorbar()命令自动创建一个表示图形各种颜色对应标签信息的颜色条。但是图形还有一点不尽如人意的地方,就是看起来有点儿“污渍斑斑“不是那么干净。这是由于颜色的改变是一个离散而非连续的过程,这并不是我们想要的效果。你当然可以通过将等高线的数量设置得非常多来解决这个问题,但是最终获得的图形性能会很不好,因为 Matplotlib必须渲染每一级的等高线。其实有更好的做法,那就是通过plt.imshow()函数来处理,它可以将二维数组渲染成渐变图。
使用imshow()函数有一些注意事项。
- plt.imshow()不支持用x轴和y轴数据设置网格,而是必须通过extent参数设置图形的坐标范围[xmin,xmax,ymin,ymax]。
- plt.imshow()默认使用标准的图形数组定义,就是原点位于左上角,而不是绝大多数等高线图中使用的左下角,这一点在显示网格数据图形时必须调整。
- plt.imshow()会自动调整坐标轴的精度以适应数据显示。可以通过plt.axis(aspect=‘image’)来设置x轴与y轴的单位。
频次直方图、数据区间划分和分布密度
hist()有许多用来调整计算过程和显示效果的选项。
histtype=‘ stepfilled’与透明性设置参数 alpha搭配使用的效果:
二维频次直方图与数据区间划分
就像将一维数组分为区间创建一维频次直方图一样,我们也可以将二维数组按照二维区间进行切分,来创建二维频次直方图。
plt.hist2d:二维频次直方图
plt.hist2d类似的函数式np.histogram2d。
plt.hexbin:六边形区间划分
二维频次直方图是由于坐标轴正交的方块分割而成的,还有一种常用的方式是用正六边形分割。Matplotlib提供的plt.hexbin满足此类需求,将二维数据集分割成蜂窝状。
核密度估计
有一种评估多维数据分布密度的常用方法是核密度估计KDE。KDE方法通过不同的平滑带宽长度( smoothing length)在拟合函数的准确性与平滑性之间作出权衡(无处不在的偏差与方差的取舍问题的一个例子)。想找到恰当的平滑带宽长度是件很困难的事, gaussian_kde通过一种经验方法试图找到输入数据平滑长度的近似最优解。
配置图例
设置图例的位置,并取消外框。
还可以用ncol参数设置图例的标签列数。还可以为图例定义圆角边框( fancybox)、增加阴影、改变外边框透明度( framealpha值),或者改变文字间距。
选择图例显示的元素
图例会默认显示所有元素的标签。如果你不想显示全部,可以通过一些图形命令来指定显示图例中的哪些元素和标签。plt.plot()命令可以一次创建多条线,返回线条实例列表。一种方法是将需要显示的线条传入plt.legend(),另一种方法是只为需要在图例中显示的线条设置标签。默认情况下图例会忽略那些不带标签的元素。
在图例中显示不同尺寸的点
同时显示多个图例
我们可以通过从头开始创建一个图例艺术家对象(legend artist),然后用底层的(lower-level)ax.add_artiest()方法在图上添加第二个图例。
配置颜色条
在Matplotlib中,颜色条是一个独立的坐标轴,可以指明图形中颜色的含义。
配置颜色条
可以通过cmap参数为图形设置颜色条的配色方案。
选择配色方案
顺序配色方案
由一组连续的颜色构成的配色方案(例如 binary或viridis)。
互逆配色方案
通常由两种互补的颜色构成,表示正反两种含义(例如RdBu或PuOr)。
定性配色方案
随机顺序的一组颜色(例如 rainbow或jet)。
颜色条刻度的限制与扩展功能的设置
Matplotlib提供了丰富的颜色条配置功能。由于可以将颜色条本身仅看作是一个plt.Axes实例,因此前面所学的所有关于坐标轴和刻度值的格式配置技巧都可以派上用场。
离散型颜色条
虽然颜色条默认都是连续的,但有时你可能也需要表示离散数据。最简单的做法就是使用plt.cm.get_cmap()函数,将适当的配色方案的名称以及需要的区间数量传进去即可。
多子图
plt.axes:手动创建子图
创建坐标轴最基本的方法就是使用p1t.axes函数。前面已经介绍过,这个函数的默认配置是创建一个标准的坐标轴,填满整张图。它还有个可选参数,由图形坐标系统的四个值构成。这四个值分别表示图形坐标系统的[bottom,Left, width, height](底坐标、左坐标、宽度、高度),数值的取值范围是左下角(原点)为0,右上角为1。
如果想要在右上角创建一个画中画,那么可以首先将x与y设置为0.65(就是坐标轴原点位于图形高度65%和宽度65%的位置),然后将x与y扩展到0,2(也就是将坐标轴的宽度与高度设置为图形的20%)。
面向对象画图接口中类似的命令有fig.add_axes()。
plt.subplot:简易网格子图
最底层的方法是用plt.subplot()在一个网格中创建一个子图。这个命令有三个整型参数—将要创建的网格子图行数、列数和索引值,索引值从1开始,从左上角到右下角依次增大。
plt.subplots_adjust命令可以调整子图之间的间隔。用面向对象接口的命令fig.ad_subplot()可以取得同样的效果。
plt.subplots:用一行代码创建网格
想隐藏内部子图的x轴与y轴标题时。出于这一需求,plt.subplots()实现了你想要的功能(需要注意此处 subplots结尾多了个s)。这个函数不是用来创建单个子图的,而是用一行代码创建多个子图,并返回一个包含子图的 NumPy数组。关键参数是行数与列数,以及可选参数 sharex与 sharey,通过它们可以设置不同子图之间的关联关系。
设置 sharex与 sharey参数之后,我们就可以自动去掉网格内部子图的标签,让图形看起来更整洁。坐标轴实例网格的返回结果是一个NumPy数组,这样就可以通过标准的数组取值方式轻松获取想要的坐标轴了。
与plt.subplot()相比,p1t. subplots()与 Python索引从0开始的习惯保持一致。
plt.Gridspec:实现更复杂的排列方式
如果想实现不规则的多行多列子图网格,plt. Gridspec()是最好的工具。plt.Gridspec()对象本身不能直接创建一个图形,它只是plt.subplot()命令可以识别的简易接口。
文字与注释
坐标变换与文字位置
- ax.transData,以数据为基准的坐标变换。
- ax.transAxes,以坐标轴为基准的坐标变换(以坐标轴维度为单位)。
- fig.transFigure,以图形为基准的坐标变换(以图形维度为单位)。
transData坐标用x轴与y轴的标签作为数据坐标。 transAxes坐标以坐标轴(图中白色矩形)左下角的位置为原点,按坐标轴尺寸的比例呈现坐标。 trans Figure坐标与之类似,不过是以图形(图中灰色矩形)左下角的位置为原点,按图形尺寸的比例呈现坐标。
箭头与注释
在 Matplotlib里面画箭头通常比你想象的要困难。虽然有一个plt.arrow()函数可以实现这个功能,但是我不推荐使用它,因为它创建出的箭头是SvG向量图对象,会随着图形分辨率的变化而改变,最终的结果可能完全不是用户想要的。我要推荐的是plt.annotate()函数。这个函数既可以创建文字,也可以创建箭头,而且它创建的箭头能够进行非常灵活的配置。
箭头的风格是通过arrowprops字典控制的。
自定义坐标轴刻度
在介绍示例之前,我们最好先对 Matplotlib图形的对象层级有更深入的理解。 Matplotlib的目标是用 Python对象表现任意图形元素。例如,figure对象其实就是一个盛放图形元素的包围盒( bounding box)。可以将每个 Matplotlib对象都看成是子对象(sub-object)的容器,例如每个 figure都会包含一个或多个axes对象,每个aXes对象又会包含其他表示图形内容的对象。
坐标轴刻度线也不例外。每个axeS都有 axis和 yaxis属性,每个属性同样包含构成坐标轴的线条、刻度和标签的全部属性。
主要刻度与次要刻度
我们发现每个主要刻度都显示为一个较大的刻度线和标签,而次要刻度都显示为一个较小的刻度线,且不显示标签。
可以通过设置每个坐标轴的 formatter与 locator对象,自定义这些刻度属性(包括刻度线的位置和标签)。
主要刻度标签和次要刻度标签的位置都是通过一个LogLocator对象(在对数图中可以看到)设置的。然而,次要刻度有个NullFormatter对象处理标签,这样标签就不会在图上显示了。
隐藏刻度与标签
最常用的刻度/标签格式化操作可能就是隐藏刻度与标签了,可以通过plt. NullLocator()与plt.NullFormatter()实现。
增减刻度数量
默认刻度标签有一个问题,就是显示较小图形时,通常刻度显得十分拥挤。数字几乎都重叠在一起,辨识起来非常困难。我们可以用plt. MaxNLocator()来解决这个问题,通过它可以设置最多需要显示多少刻度。根据设置的最多刻度数量, Matplotlib会自动为刻度安排恰当的位置。
花哨的刻度格式
可以通过设置一个MultipleLocator来实现将刻度放在你提供的数值的倍数上。让图形会更加自然。
格式生成器与定位器小结
Matplotlib自定义:配置文件与样式表
手动配置图形
每次都要手动配置一番太麻烦了,可以配置一次默认图形将其应用到所有图形上。
修改默认配置:rcParams
Matplotlib每次加载时,都会定义一个运行时配置(rc),其中包含了所有你创建的图形元素的默认风格。你可以用plt.rc简便方法随时修改这个配置。
样式表
默认风格
FiveThirtyEight风格
ggplot风格
bmh风格
黑色背景风格
灰度风格
Seaborn风格
用Matplotlib画三维图
我们可以导入 Matplotlib自带的plot3d工具箱来画三维图。
导入这个子模块之后,就可以在创建任意一个普通坐标轴的过程中加入projection=‘3d’关键字,从而创建一个三维坐标轴。
三维数据点与线
最基本的三维图是由(x,y,z)三维坐标点构成的线图与散点图。与前面介绍的普通二维图类似,可以用 ax.plot3D与ax.scatter3D函数来创建它们。三维图函数的参数与前面二维图函数的参数基本相同。
默认情况下,散点会自动改变透明度,以在平面上呈现出立体感。
三维等高线
与之前的等高线类似,mplot3d也有用同样的输入数据创建三维晕渲( relief)图的工具。与二维ax.contour图形一样,ax.contour3D要求所有数据都是二维网格数据的形式,并且由函数计算z轴数值。
线框图和曲面图
曲面图与线框图类似,只不过线框图的每个面都是由多边形构成的。只要增加一个配色方案来填充这些多边形。
画曲面图需要二维数据,但可以不是直角坐标系(也可以用极坐标)。
曲面三角剖分
用Basemap可视化地理数据
地理数据可视化是数据科学中一种十分常见的可视化类型。 Matplotlib做此类可视化的主要工具是 Basemap工具箱。
安装并导入 Basemap工具箱后,只用几行代码就可以画出地理图形。
用Seaborn做数据可视化
虽然 Matplotlib已经证明了自己绝对是一款超级实用且流行的数据可视化工具,但是即使骨灰粉也不得不承认它不支持的功能还有很多。
Seaborn在Matplotlib的基础上开发了一套API,为默认的图形样式和颜色设置提供了理智的选择,为常用的统计图形定义了许多简单的高级函数,并与Pandas dataFrame的功能有机结合。
Seaborn与Matplotlib
Seaborn不仅有许多高级的画图功能,而且可以改写 Matplotlib的默认参数,从而用简单的Matplotlib脚本获得更好的效果。可以用 Seaborn的set()方法设置样式。